//+--------------------------------------------------------------------------------
//| Copyright (c) 2012 - 2013 ### an.vuongngocduy
//| This file is a part of Compact Game Engine (CGE)
//+--------------------------------------------------------------------------------
#include "cgeFileStream.h"

namespace cge
{
	namespace io
	{
		//=========================================================================================
		FileStream::FileStream(const String& filePath, EFileOpenMode mode)
			: mFile(null)
		{
			mMode = mode;
			switch(mMode)
			{
			case FileOpenMode::OpenRead:
				mFile = fopen(filePath.Chars(), "rb");
				break;

			case FileOpenMode::OpenWrite: 
			case FileOpenMode::OpenReadWrite:
				mFile = fopen(filePath.Chars(), "rb+");
				break;

			case FileOpenMode::CreateWrite:
				mFile = fopen(filePath.Chars(), "wb");
				break;

			case FileOpenMode::CreateReadWrite:
				mFile = fopen(filePath.Chars(), "wb+");
				break;

			case FileOpenMode::Append:
				mFile = fopen(filePath.Chars(), "ab+");
				break;

			default: break;
			}

			if(mFile != null) 
			{
				mFilePath = filePath;
				fseek(mFile, 0, SEEK_END);
				mFileSize = ftell(mFile);
				fseek(mFile, 0, SEEK_SET);
			}
		}

		//=========================================================================================
		FileStream::~FileStream()
		{
			finalize();
		}

		//=========================================================================================
		const String& FileStream::GetFilePath() const
		{
			return mFilePath;
		}

		//=========================================================================================
		FileStream::operator Stream&() const
		{
			return *((Stream*)this);
		}

		//=========================================================================================
		b8 FileStream::finalize()
		{
			if(mFile != null)
				return (fclose(mFile) == 0);
			return false;
		}

		//=========================================================================================
		u32 FileStream::size()
		{
			return mFileSize;
		}
		
		//=========================================================================================
		u32 FileStream::position()
		{
			if(mFile != null)
				return ftell(mFile);
			return 0;
		}

		//=========================================================================================
		u32 FileStream::read(u8* dst, u32 count)
		{
			if((mMode & FileOpenMode::OpenRead) != 0 
				&& count != 0
				&& dst != null 
				&& mFile != null )
			{
				u32 n = fread(dst, 1, count, mFile);
				if(n != count)
				{
					if(feof(mFile)) // end of file
						return n;

					if(ferror(mFile)) // TO DO(an.vuong) something happened so need some debug log here or something else...
						return 0;
				}
				return n;
			}
			return 0;
		}
		
		//=========================================================================================
		u32 FileStream::write(u8* src, u32 count)
		{
			if((mMode & FileOpenMode::OpenWrite) != 0 
				&& count != 0
				&& src != null 
				&& mFile != null )
			{
				u32 n = fwrite(src, 1, count, mFile);
				if(n != count)
				{
					s32 err = ferror(mFile); // TO DO : something happened so need some debug log here or something else...
					return 0;
				}
				return n;
			}
			return 0;
		}
	
		//=========================================================================================
		b8 FileStream::seek(u32 offset, b8 fromBeginning)
		{
			if(mFile != null)
			{
				if(fseek(mFile, offset, fromBeginning ? SEEK_SET : SEEK_CUR) == 0)
					return true;
			}
			return false;
		}

		//=========================================================================================
	}
}